package algo3.grupo3.vista;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Iterator;
import java.util.LinkedList;

import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.Timer;

import algo3.grupo3.controlador.ControlTecladoJugador;
import algo3.grupo3.controlador.LogicaJuego;
import algo3.grupo3.modelo.BloqueAcero;
import algo3.grupo3.modelo.BloqueConArticulo;
import algo3.grupo3.modelo.Bombita;
import algo3.grupo3.modelo.Chala;
import algo3.grupo3.modelo.Enemigo;
import algo3.grupo3.vista.Entidad;
import algo3.grupo3.modelo.Bomba;

public class VentanaJuego extends JFrame implements ActionListener{

	private static final long serialVersionUID = 1L;
	
	private Timer timer= new Timer(DELAY_TIMER,this);
	public final static int ANCHO = 800, ALTO = 600, DELAY_TIMER = 300;//antes 200 antes 300
	
	private ControlTecladoJugador ctj= new ControlTecladoJugador();/*controla las acciones de bombita y ademas permite pausar el juego
	presionando la tecla P */
	
	//LogicaJuego logicaJuego= new LogicaJuego(DELAY_TIMER);
	private LogicaJuego logicaJuego;
	
	private int anchoMapa= 10, altoMapa= 10;
	
	private int estadoJuego;
	public static final int NO_INICIADO= 0,JUGANDO=1,PAUSA=2,TERMINADO=3,GANADO= 4;
		
	public VentanaJuego(LogicaJuego lj){
		super("VentanaJuego");
		this.inicializarVentanaJuego();
		this.establecerLogicaJuego(lj);
		Entidad.establecerLogicaJuego(logicaJuego);
		logicaJuego.establecerVentanaJuego(this);
		estadoJuego= NO_INICIADO;
		
		ctj.setearVentanaJuego(this);
		this.addKeyListener(ctj);

	}//fin de constructor
	
	/*public VentanaJuego(int anm,int alm){
		this();
		this.establecerAltoMapa(alm);
		this.establecerAnchoMapa(anm);
		this.establecerEscalas();
	}//fin de constructor*/
	
	public void establecerAnchoMapa(int anm){
		if(anm<=10)
			return;
		this.anchoMapa= anm;
	}//fin de establecerAnchoMapa
	
	public void establecerAltoMapa(int alm){
		if(alm<=10)
			return;
		this.altoMapa= alm;
	}//fin de establecerAltoMapa
	
	public void establecerEscalas(){
		int anchoEscala= (int)(ANCHO/anchoMapa);
		int altoEscala= (int)(ALTO/altoMapa);
		Entidad.cambiarAnchoEscalaPosicion(anchoEscala);
		Entidad.cambiarAltoEscalaPosicion(altoEscala);
	}//fin de establecerEscalas
	
	private void inicializarVentanaJuego(){
		super.setSize(ANCHO, ALTO);
		super.setResizable(false);//no se podra cambiar el tamanio de la ventana durante la ejecucion
		super.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);// aplicacion terminara al cerrar la ventana
		super.setVisible(true);//la ventana se vuelve visible
	}//fin de inicializarVentanaJuego	
	
	public void iniciarJuego(){
		this.timer.start();
		this.estadoJuego= JUGANDO;
		//this.logicaJuego.obtenerEntidadBombita().descongelar();
	}//fin de iniciarJuego
	
	public void pausarJuego(){
		this.timer.stop();
		this.estadoJuego= PAUSA;
		//this.logicaJuego.obtenerEntidadBombita().congelar();
		repaint();
	}//fin de pausarJuego
	
	public void terminarJuego(){
		this.timer.stop();
		this.estadoJuego= TERMINADO;
	}//fin de terminarJuego
	
	public void ganarJuego(){
		this.timer.stop();
		this.estadoJuego= GANADO;
	}//fin de ganarJuego
	
	public int obtenerEstadoJuego(){
		return this.estadoJuego;
	}//fin de obtenerEstadoJuego
	
	/**FIN DE METODOS DE INICIALIZACION***************************************** */
	
	@Override
	public synchronized void paint(Graphics gvj){
		Graphics2D gvj2d= (Graphics2D)gvj;
		Image buffer= createImage(ANCHO,ALTO);
		Graphics2D gb = (Graphics2D)buffer.getGraphics();
		
		this.limpiarEscena(gb);//limpia la imagen del buffer con una imagen blanca
		
		switch(this.estadoJuego){
		case NO_INICIADO:
			this.dibujarMenuInicio(gb);
			break;
		case JUGANDO:
			this.dibujarTablero(gb);
			this.dibujarSobreBuffer(gb);		
			this.dibujarDatos(gb);
			break;
		case PAUSA:
			this.dibujarPausaJuego(gb);
			break;
		case TERMINADO:
			this.dibujarMenuJuegoTerminado(gb);
			break;
		case GANADO:
			this.dibujarMenuJuegoGanado(gb);
			break;
		}
		
		this.dibujarBuffer(buffer, gvj2d);//se dibuja el buffer en la ventana
		
		gvj2d.dispose();
		gb.dispose();//libero los recursos de graficos solicitados
		
	}//fin de paint	
	
	private void dibujarMenuJuegoGanado(Graphics2D gb) {
		
		Image imagenJuegoGanado= (new ImageIcon("images//bombermanWin.jpg")).getImage();
		gb.setColor(Color.BLACK);
		int medioX= (int)(ANCHO/2);
		int medioY= (int)(ALTO/2);
		int cuartoX= (int)(medioX/2);
		medioY+= 80;
		
		gb.drawImage(imagenJuegoGanado, 0, 0, null);
		gb.drawString("1) Reiniciar Juego", cuartoX, medioY);
		gb.drawString("2) Cargar partida", cuartoX, medioY+20);
		
	}//fin de dibujarMenuJuegoGanado

	private void dibujarMenuJuegoTerminado(Graphics2D gb) {
		Image imagenGameOver= (new ImageIcon("images//gameOver.jpg")).getImage();
		gb.setColor(Color.WHITE);
		int medioX= (int)(ANCHO/2);
		int medioY= (int)(ALTO/2);
		medioY+= 80;
		
		gb.drawImage(imagenGameOver, 0, 0, null);
		gb.drawString("1) Reiniciar nivel", medioX, medioY);
		gb.drawString("2) Cargar partida", medioX, medioY + 20);
		
		imagenGameOver= null;
		
	}//fin de dibujarMenuJuegoTerminado
	
	private void dibujarMenuInicio( Graphics2D gb ){
		Image imagenInicio= (new ImageIcon("images//imagenInicio.png")).getImage();
		int medioX= (int)(ANCHO/2-imagenInicio.getWidth(null)/2);
		int medioY= (int)(ALTO/2-imagenInicio.getHeight(null)/2 );
		
		gb.setColor(Color.BLACK);
		int posicionMenuY= medioY+imagenInicio.getHeight(null);
		
		gb.drawString("1) Iniciar juego nuevo", medioX, posicionMenuY);
		gb.drawString("2) Cargar partida", medioX, posicionMenuY+ 20);
		
		gb.drawImage(imagenInicio, medioX, medioY, null);
		imagenInicio= null;
	}//fin de dibujarMenuInicio
	
	private void dibujarPausaJuego( Graphics2D gb ){
		gb.setColor(Color.BLACK);
		gb.drawString("Juego pausado presione P para continuar", (int)(ANCHO/2) , (int)(ALTO/2));
		gb.drawString("1) Guardar partida", (int)(ANCHO/2) , (int)(ALTO/2+20));
		gb.drawString("2) Cargar partida", (int)(ANCHO/2) , (int)(ALTO/2)+40);
		gb.drawString("3) Reiniciar Nivel", (int)(ANCHO/2) , (int)(ALTO/2)+60);
	}//fin de dibujarPausaJuego
	
	private void dibujarSobreBuffer(Graphics2D gb){
		
		this.dibujarBombita(gb);//dibuja a Bombita
		this.dibujarBombas(gb);//se dibujan las bombas en la imagen buffer
		this.dibujarBloques(gb);//se dibujan los bloques
		this.dibujarEnemigos(gb);//se dibujan los enemigos
		this.dibujarArticulos(gb);//se dibujan los articulos
		
	}//fin de dibujarentidades
	

	private void dibujarDatos(Graphics2D gb){
		gb.setColor(Color.BLACK);
		this.dibujarTiempo(gb);
		this.dibujarPosicionBombita(gb);
		this.dibujarPuntos(gb);
	}//fin de dibujarDatos
	
	private void dibujarPuntos(Graphics2D gb){
		gb.drawString("Puntos: "+logicaJuego.obtenerPuntos(), ANCHO-100, ALTO-60);
	}//fin de dibujarPuntos
	
	
	private void dibujarBloques(Graphics2D g2d) {
		this.dibujarBloquesDeAcero(g2d);
		
		LinkedList<EntidadBloqueConArticulo> listaDeBloquesConArticulo;
		listaDeBloquesConArticulo = logicaJuego.obtenerListaBloquesConArticulo();
		
		if(listaDeBloquesConArticulo.isEmpty())
			return;
		Iterator<EntidadBloqueConArticulo> iterador = listaDeBloquesConArticulo.iterator();
		EntidadBloqueConArticulo ebca;
		while(iterador.hasNext()){
			ebca = (EntidadBloqueConArticulo)iterador.next();
			ebca.dibujar(g2d);
		} 
		
		iterador = null;
		listaDeBloquesConArticulo= null;
		System.gc();
		
	}//fin de dibujarBloques

	private void dibujarArticulos(Graphics2D g2d) {
		this.dibujarChalas(g2d);
		this.dibujarTimers(g2d);
		this.dibujarToleToles(g2d);
		this.dibujarSalida(g2d);
	}
	
	private void dibujarSalida(Graphics2D g2d) {
		EntidadSalida salida;
		salida = logicaJuego.obtenerSalida();
		
		if(salida == null)
			return;
		
		salida.dibujar(g2d);
		
		salida = null;
		System.gc();
		
	}

	private void dibujarToleToles(Graphics2D g2d) {
		LinkedList<EntidadArtToleTole> listaDeToleToles;
		listaDeToleToles = logicaJuego.obtenerListaToleTole();
		
		if(listaDeToleToles.isEmpty())
			return;
		Iterator<EntidadArtToleTole> iterador = listaDeToleToles.iterator();
		EntidadArtToleTole entToleTole;
		while(iterador.hasNext()){
			entToleTole = (EntidadArtToleTole)iterador.next();
			entToleTole.dibujar(g2d);
		} 
		
		iterador = null;
		listaDeToleToles = null;
		System.gc();
		
	}

	private void dibujarChalas(Graphics2D g2d) {
		
		LinkedList<EntidadChala> listaDeChalas;
		listaDeChalas = logicaJuego.obtenerListaChalas();
		
		if(listaDeChalas.isEmpty())
			return;
		Iterator<EntidadChala> iterador = listaDeChalas.iterator();
		EntidadChala entChala;
		while(iterador.hasNext()){
			entChala = (EntidadChala)iterador.next();
			entChala.dibujar(g2d);
		} 
		
		iterador = null;
		listaDeChalas = null;
		System.gc();
		
	}
	
	private void dibujarTimers(Graphics2D g2d) {
		
		LinkedList<EntidadTimer> listaDeTimers;
		listaDeTimers = logicaJuego.obtenerListaTimers();
		
		if(listaDeTimers.isEmpty())
			return;
		Iterator<EntidadTimer> iterador = listaDeTimers.iterator();
		EntidadTimer entTimer;
		while(iterador.hasNext()){
			entTimer = (EntidadTimer)iterador.next();
			entTimer.dibujar(g2d);
		} 
		
		iterador = null;
		listaDeTimers = null;
		System.gc();
		
	}

	private void dibujarBloquesDeAcero(Graphics2D g2d) {
		
		LinkedList<EntidadBloqueAcero> listaDeBloquesAcero= logicaJuego.obtenerListaBloquesAcero();
		
		if(listaDeBloquesAcero.isEmpty())
			return;
		Iterator<EntidadBloqueAcero> iterador = listaDeBloquesAcero.iterator();
		EntidadBloqueAcero ebA;
		while(iterador.hasNext()){
			ebA = (EntidadBloqueAcero)iterador.next();
			ebA.dibujar(g2d);
		} 
		
		iterador = null;
		listaDeBloquesAcero= null;
		System.gc();
		
	}//fin de dibujarBloquesDeAcero

	public void dibujarPosicionBombita(Graphics2D g2d){
		EntidadBombita entidadBombita= logicaJuego.obtenerEntidadBombita();
		
		if(entidadBombita== null)
			return;
		
		if(!entidadBombita.objetoSigueActivo())
			return;
		
		int[] coordenadasBombita= entidadBombita.obtenerObjeto().obtenerCoordenadas();
		
		g2d.drawString("CoordenadasBombita: "+coordenadasBombita[0]+", "+coordenadasBombita[1],
				ANCHO- 150 ,ALTO-40 );
		
		coordenadasBombita= null;
		entidadBombita= null;
		System.gc();
	}//fin de dibujarPosicionBombita
	
	public void dibujarTiempo(Graphics2D g2d){
		g2d.drawString("Tiempo: "+logicaJuego.obtenerTiempo(), ANCHO-100, ALTO-20);
	}//fin de dibujarTiempo
	
	public void limpiarEscena(Graphics2D g2d ){
		g2d.setColor(Color.WHITE);
		g2d.fillRect(0, 0, ANCHO, ALTO);
		
	}//fin de limpiarVentana
	
	private void dibujarTablero(Graphics2D g2d){
		g2d.setColor(Color.lightGray);
		int anchoEscalaPosicion= Entidad.obtenerAnchoEscalaPosicion();
		int altoEscalaPosicion= Entidad.obtenerAltoEscalaPosicion();
		for(int j=0; j<altoMapa ; j+=2)
			for(int i= 0; i<anchoMapa; i+=2){
				g2d.fillRect(anchoEscalaPosicion + i*anchoEscalaPosicion, 
						altoEscalaPosicion+j*altoEscalaPosicion, anchoEscalaPosicion, altoEscalaPosicion);
			}
	
		for(int j=1; j<altoMapa ; j+=2)
			for(int i= 1; i<anchoMapa; i+=2){
				g2d.fillRect(anchoEscalaPosicion + i*anchoEscalaPosicion, 
						altoEscalaPosicion+j*altoEscalaPosicion, anchoEscalaPosicion, altoEscalaPosicion);
			}
		
		g2d.setColor(Color.cyan);
		for(int j=0; j<altoMapa ; j+=2)
			for(int i= 1; i<anchoMapa; i+=2){
				g2d.fillRect(anchoEscalaPosicion + i*anchoEscalaPosicion, 
						altoEscalaPosicion+j*altoEscalaPosicion, anchoEscalaPosicion, altoEscalaPosicion);
			}
		
		for(int j=1; j<altoMapa ; j+=2)
			for(int i= 0; i<anchoMapa; i+=2){
				g2d.fillRect(anchoEscalaPosicion + i*anchoEscalaPosicion, 
						altoEscalaPosicion+j*altoEscalaPosicion, anchoEscalaPosicion, altoEscalaPosicion);
			}
		
	}//fin de dibujarTablero
	
	
	public void dibujarBombas(Graphics2D g2d){
		
		LinkedList<EntidadBomba> listaBombas= logicaJuego.obtenerListaBombas();
		
		if(listaBombas.isEmpty())
			return;
		Iterator<EntidadBomba> iterador= listaBombas.iterator();
		EntidadBomba eb;
		while(iterador.hasNext()){
			eb= iterador.next();
			eb.dibujar(g2d);
		}
		
		iterador= null;
		listaBombas= null;
		System.gc();
		
	}//fin de dibujarBombas
	
	public void dibujarBombita(Graphics2D g2d){
		
		EntidadBombita entidadBombita= logicaJuego.obtenerEntidadBombita();
		
		if(entidadBombita!=null)
			entidadBombita.dibujar(g2d);
	}//fin de dibujarBombita
	
	public void dibujarEnemigos(Graphics2D g2d){
		
		LinkedList<EntidadEnemigo> listaEnemigos = logicaJuego.obtenerListaEnemigos();
		
		if(listaEnemigos.isEmpty())
			return;
		Iterator<EntidadEnemigo> iterador= listaEnemigos.iterator();
		EntidadEnemigo ee;
		while(iterador.hasNext()){
			ee= iterador.next();
			ee.dibujar(g2d);
		}
		
		iterador= null;
		listaEnemigos= null;
		System.gc();
		
	}//fin de dibujarEnemigos
	
	public void dibujarBuffer(Image buffer, Graphics2D g2d){
		if(buffer== null || g2d == null)
			return;
		g2d.drawImage(buffer, 0, 0, null);
	}//fin de dibujarBuffer
	
	
	/**FIN DE METODOS DE DIBUJO***************************************** */
		
	
	public void actionPerformed(ActionEvent ae){
		
		this.repaint();
		logicaJuego.actualizar();
	}//fin de actionPerformed, actua como gameLoop
	
	
	public synchronized void agregarBomba(Bomba b){
		logicaJuego.agregarBomba(b);
	}//fin de agregarBomba
	
	
	public synchronized void agregarJugador(Bombita b){
		if(b == null)
			return;
		//ctj = new ControlTecladoJugador();
		EntidadBombita eb = new EntidadBombita(b);
		ctj.cargarBombita(eb);
		//ctj.setearVentanaJuego(this);
		//this.addKeyListener(ctj);
		logicaJuego.agregarJugador(eb);		
		
	}//fin de agregarJugador
	
	public void establecerControlTecladoJugador(ControlTecladoJugador c){
		this.ctj= c;
	}//fin de establecerControlTecladoJugador
	
	public synchronized void agregarBloqueConArticulo(BloqueConArticulo bca){
		logicaJuego.agregarBloqueConArticulo(bca);
	}//fin de agregarBloqueConArticulo
	
	public synchronized void agregarBloqueAcero(BloqueAcero ba){
		logicaJuego.agregarBloqueAcero(ba);
	}//fin de agregarBloqueAcero
	
	public synchronized void agregarEnemigo(Enemigo e){
		logicaJuego.agregarEnemigo(e);
	}//fin de agregarEnemigo
	
	public synchronized void agregarChala(Chala unaChala){
		logicaJuego.agregarChala(unaChala);
	}//fin de agregarChala
	
	public synchronized void establecerLogicaJuego(LogicaJuego lj){
		if(lj== null)
			return;
		this.logicaJuego= lj;
	}//fin de establecerLogicaJuego
	
	
	/**FIN DE METODOS DE AGREGADO DE ELEMENTOS ---------------------------------------------- */
	
	public boolean juegoEstaCorriendo(){
		return this.timer.isRunning();
	}//fin de juegoEstaCorriendo
	
	public void guardarPartida(){
		this.logicaJuego.guardarPartida();
	}//fin de guardarPartida
	
	public void cargarPartida(){
		this.logicaJuego.cargarPartida();
	}//fin de cargarPartida
	
	public void reiniciarJuego(){
		this.logicaJuego.reiniciarJuego();
	}//fin de reiniciarJuego
	
	public void reiniciarNivel(){
		this.logicaJuego.reiniciarNivel();
	}//fin de reiniciarNivel
	
	public LogicaJuego obtenerLogicaJuego(){
		return this.logicaJuego;
	}//fin de obtenerLogicaJuego
	
	public int obtenerAnchoMapa(){
		return this.anchoMapa;
	}//fin de obtenerAnchoMapa
	
	public int obtenerAltoMapa(){
		return this.altoMapa;
	}//fin de obtenerAltoMapa
	
	public ControlTecladoJugador obtenerControlTecladoJugador(){
		return this.ctj;
	}//fin de obtenerControlTecladoJugador
	
	/**FIN DE METODOS DE MEMORIA ------------------------------------------------------- */
	
	/*****************************************************FIN DE METODOS*/
	
	
}//fin de VentanaJuego
/*version SEGURA 
 * BUG DE EXPLOSION AGREGADO
 * LOGICA DEL JUEGO ALGO SEPARADA DE VENTANA-JUEGO*/
